package com.java.simple.study.jvm.stringtable;

/**
 * @author zhoujunlin
 * @date 2022年09月04日 22:31
 * @desc
 */
public class StringTest5 {

    public static void main(String[] args) {
        //test1();
        //test2();
        //test3();
        test5();
    }

    public void test7() {
        /**
         *  对象1：new StringBuilder()
         *  对象2： new String("a")
         *  对象3： 常量池中的"a"
         *  对象4： new String("b")
         *  对象5： 常量池中的"b"
         *  深入剖析： StringBuilder的toString():
         *  对象6 ：new String(value, 0, count)
         *  强调一下，toString()的调用，在字符串常量池中，没有生成"ab"
         *   0 new #3 <java/lang/StringBuilder>
         *  3 dup
         *  4 invokespecial #4 <java/lang/StringBuilder.<init> : ()V>
         *  7 new #5 <java/lang/String>
         * 10 dup
         * 11 ldc #6 <a>
         * 13 invokespecial #7 <java/lang/String.<init> : (Ljava/lang/String;)V>
         * 16 invokevirtual #8 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
         * 19 new #5 <java/lang/String>
         * 22 dup
         * 23 ldc #9 <b>
         * 25 invokespecial #7 <java/lang/String.<init> : (Ljava/lang/String;)V>
         * 28 invokevirtual #8 <java/lang/StringBuilder.append : (Ljava/lang/String;)Ljava/lang/StringBuilder;>
         * 31 invokevirtual #10 <java/lang/StringBuilder.toString : ()Ljava/lang/String;>
         * 34 astore_1
         * 35 return
         */
        String ab = new String("a") + new String("b");
    }

    public void test6() {
        /**
         * 这里会创建2个对象 查看字节码即知
         * 一个对象是：new关键字在堆空间创建的
         * 另一个对象是：字符串常量池中的对象"ab"。 字节码指令：ldc
         *  0 new #3 <java/lang/String>
         *  3 dup
         *  4 ldc #4 <ab>
         *  6 invokespecial #5 <java/lang/String.<init> : (Ljava/lang/String;)V>
         *  9 astore_1
         * 10 return
         */
        String ab = new String("ab");
    }

    public static void test5() {
        long start = System.currentTimeMillis();
        //method1(10_0000); //花费时间为3642ms
        method2(10_0000); //花费时间为0ms
        long end = System.currentTimeMillis();
        System.out.println("花费时间为" + (end - start) + "ms");
    }

    public static void method1(int highLevel) {
        String src = "";
        for (int i = 0; i < highLevel; i++) {
            // 每次循环都会创建StringBuilder、String
            src = src + "a";
        }
    }

    public static void method2(int highLevel) {
        StringBuilder src = new StringBuilder();
        for (int i = 0; i < highLevel; i++) {
            src.append("a");
        }
    }


    public static void test4() {
        /**
         * 1. 字符串变量拼接不一定使用的是StringBuilder
         *    如果拼接符号左右两边都是字符串常量或者常量引用 则仍然使用编译期优化 即非StringBuilder的方式
         * 2. 针对final修饰类、方法、基本数据类型、引用数据类型的量的结构时  能使用final的时候建议使用上
         */
        final String s1 = "a";
        final String s2 = "b";
        String s3 = "ab";
        String s4 = s1 + s2;
        System.out.println(s3 == s4); // true
    }

    public static void test3() {
        String s1 = "a";
        String s2 = "b";
        String s3 = "ab";

        /*
        如下s1+s2的执行细节
        StringBuilder s = new StringBuilder();
        s.append("a");
        s.append("b");
        s.toString();  -> 约等于new String("ab")
        补充：在jdk5.0之后使用的StringBuilder  之前是StringBuffer
        */

        String s4 = s1 + s2;
        System.out.println(s3 == s4); // false
    }

    public static void test2() {
        // 拼接前后，只要其中有一个是变量，结果就在堆中
        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE" + "hadoop";

        String s5 = s1 + "hadoop";
        String s6 = "javaEE" + s2;
        String s7 = s1 + s2;

        System.out.println(s3 == s4);  // true
        System.out.println(s3 == s5);  // false
        System.out.println(s3 == s6); // false
        System.out.println(s3 == s7); // false
        System.out.println(s5 == s6);  //false
        System.out.println(s5 == s7);  //false
        System.out.println(s6 == s7);  //false

        // 调用 intern() 方法，则主动将字符串对象存入字符串常量池中，并将其地址返回
        String s8 = s6.intern();
        System.out.println(s3 == s8); // true
    }

    public static void test1() {
        // 常量与常量的拼接结果在常量池，原理是编译期优化
        // 编译期优化  "abc"
        String s1 = "a" + "b" + "c";
        String s2 = "abc";
        System.out.println(s1 == s2); // true
        System.out.println(s1.equals(s2));  //true
    }

}
